﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Security.Permissions;
using LibYanu.Security.Model;
using LibYanu.Security.DTO;
using LibYanu.Security;
using NHibernate.Criterion;
using System.Web.Configuration;
using System.Configuration.Provider;

namespace LibYanu.Web.Provider
{
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class YanuRoleProvider : RoleProvider
    {
        private string _applicationName;
        
        

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            if (usernames.Length > 0 && roleNames.Length > 0)
            {
                foreach (var s in roleNames)
                {
                    using (var sc = new SecurityScope())
                    using (var tx = sc.Session.BeginTransaction())
                    {
                        var r = sc.Session.CreateCriteria(typeof(AspnetRole), "r")
                                .Add(Expression.Eq("r.RoleName", s))
                                .FutureValue<AspnetRole>();
                        if (r != null)
                        {
                            var rdm = r.Value;
                            var lu = new List<AspnetUser>();
                            foreach (string unm in usernames)
                            {
                                var usr = sc.Session.CreateCriteria(typeof(AspnetUser), "user")
                                         .Add(Expression.Eq("user.UserName", unm))
                                         .UniqueResult<AspnetUser>();
                                if (usr != null)
                                {  
                                        rdm.AspnetUsers.Add(usr);                                        
                                        sc.Session.Update(rdm);
                                }
                            }
                            try
                            {
                                tx.Commit();

                            }
                            catch (Exception ex)
                            {
                                tx.Rollback();
                            }                            
                        }
                    }
                }
            }
            else
            {
                throw new Exception("Username and rolename cannot be empty");
            }
        }

        public bool AddUsersToRoles(string[] usernames, string roleNames)
        {
            try
            {
                AddUsersToRoles(usernames, new string[] { roleNames });
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        public bool AddRoleToUser(string[] roleNames, string usernames)
        {
            try
            {
                AddUsersToRoles(new string[] { usernames }, roleNames);
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            
        }


        public override string ApplicationName
        {
            get { return _applicationName; }
            set { _applicationName = value; }
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            //base.Initialize(name, config);
            ApplicationName = WebConfigurationManager.AppSettings["ApplicationName"];

        }


        public override void CreateRole(string roleName)
        {
            CreateRole(roleName, null, new AplicationOp().getApplicationDtoByName(ApplicationName));
        }

        public bool CreateRole(string roleName, string description)
        {
            return CreateRole(roleName, description, new AplicationOp().getApplicationDtoByName(ApplicationName));
        }

        public bool CreateRole(string roleName, string description, AspnetApplicationDto app)
        {
            if (roleName != string.Empty)
                if (!RoleExists(roleName))
                {
                    var mdl = new AspnetRoleDto();

                    mdl.Description = description;
                    mdl.LoweredRoleName = roleName.ToLower();
                    mdl.RoleName = roleName;

                    var dm = mdl.ToEntity();

                    if (app != null)
                        dm.AspnetApplication = app.ToEntity();

                    using (var sc = new SecurityScope())
                    using (var tx = sc.Session.BeginTransaction())
                    {
                        try
                        {

                            sc.Session.Save(dm);
                            tx.Commit();
                            return true;
                        }
                        catch (Exception ex)
                        {

                            throw ex;
                        }

                    }
                }
            return false;
        }


        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            using (var sc = new SecurityScope())
            using(var tx= sc.Session.BeginTransaction())
            {
                var res = sc.Session.CreateCriteria(typeof(AspnetRole), "rl")
                         .Add(Expression.Eq("rl.RoleName", roleName))
                         .FutureValue<AspnetRole>();
                var mdl = res.Value;

                try
                {
                    sc.Session.Delete(mdl);
                    tx.Commit();
                    return true;
                }
                catch (Exception ex)
                {

                    throw ex;
                }
                    //.SetProjection(Projections.RowCount())
                         //.UniqueResult<AspnetRole>();

                

            }
            return false;
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            using (var sc = new SecurityScope())
            {
                try
                {
                    var res = sc.Session.CreateCriteria(typeof(AspnetRole), "r")
                              .Add(Expression.Eq("r.RoleName", roleName))
                              //.Add(Expression.Eq("r.AspnetUsers.UserName", usernameToMatch))                              
                              .CreateCriteria("r.AspnetUsers", "usr")
                              .Add(Expression.Eq("usr.UserName", usernameToMatch))
                              .UniqueResult<AspnetRole>();                              

                    List<string> rslt= new List<string>();
                  //  var k = res.AspnetUsers.Where(x => x.UserName == usernameToMatch).ToArray();
                   

                    foreach (var s in res.AspnetUsers.Where(x => string.Compare( x.UserName, usernameToMatch,true)==0))
                    {
                        rslt.Add(s.UserName);
                    }

                    
                    return rslt.ToArray();
                        
                }
                catch (Exception ex)
                {

                    throw ex;
                }
            }
        }

        public IEnumerable<AspnetRoleDto> GetAllModelRole()
        {
            using (var sc = new SecurityScope())
            {
                var res = sc.Session.CreateCriteria(typeof(AspnetRole), "r")
                         .List<AspnetRole>();
                return res.ToDtos();

            }
        }

        public override string[] GetAllRoles()
        {
            using (var sc = new SecurityScope())
            {
                var res = sc.Session.CreateCriteria(typeof(AspnetRole), "rl")
                            .SetProjection(Projections.Property("rl.RoleName"))
                            .List<string>().Distinct();


                return res.ToArray();
            }
        }

        public AspnetRoleDto GetRoleByName(string RoleName)
        {
            using (var sc = new SecurityScope())
            {
                var res = sc.Session.CreateCriteria(typeof(AspnetRole), "rl")
                        .Add(Expression.Eq("rl.RoleName", RoleName))
                        .UniqueResult<AspnetRole>();
                return res.ToDto();
            }
        }
        public override string[] GetRolesForUser(string username)
        {
            throw new NotImplementedException();
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            throw new NotImplementedException();
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            using(var sc= new SecurityScope())
            using (var tx = sc.Session.BeginTransaction())
            {

                try
                {
                    foreach (string rn in roleNames)
                    {
                        var rl = sc.Session.CreateCriteria(typeof(AspnetRole), "r")
                                .Add(Expression.Eq("r.RoleName", rn))
                                .UniqueResult<AspnetRole>();
                        //.Future<AspnetRole>();
                        List<AspnetUser> rldel = new List<AspnetUser>();
                        foreach (AspnetUser u in rl.AspnetUsers)
                            foreach (string s in usernames)
                            {
                                if (string.Compare(u.UserName, s, true) == 0)
                                    rldel.Add(u);
                            }


                        if (rldel.Count > 0)
                        {
                            foreach (var x in rldel)
                                rl.AspnetUsers.Remove(x);
                            sc.Session.SaveOrUpdate(rl);
                        }
                    }

                    tx.Commit();
                }
                catch (Exception ex)
                {
                    tx.Rollback();
                    throw new ProviderException(ex.Message);
                    
                }
                

            }
        }

        public override bool RoleExists(string roleName)
        {
            return GetRoleByName(roleName) != null;
        }
    }
}
